package com.dries.chat.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dries.chat.entity.ChatMsg;
import com.dries.chat.enums.MsgActionEnum;
import com.dries.chat.enums.MsgSignFlagEnum;
import com.dries.chat.enums.MsgTypeEnum;
import com.dries.chat.mapper.ChatMsgMapper;
import com.dries.chat.netty.UserChannelRel;
import com.dries.chat.netty.UserGroupChannelRel;
import com.dries.chat.service.IChatMsgService;
import com.dries.chat.vo.ChatMsgVo;
import com.dries.chat.vo.DataContent;
import com.dries.portal.consts.MsgTypeConstant;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Service("chatMsgService")
public class ChatMsgServiceImpl extends ServiceImpl<ChatMsgMapper, ChatMsg> implements IChatMsgService {

    @Resource
    private ChatMsgMapper chatMsgDao;

    private static final DateTimeFormatter formatter =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 保存聊天消息到数据库
     *
     * @param chat
     * @return
     */
    @Override
    public String saveMsg(ChatMsgVo chat) {

        ChatMsg msgDB = new ChatMsg();
        msgDB.setSendUserId(Long.valueOf(chat.getSenderId()));
        if (chat.getReceiverId() != null) {
            msgDB.setAcceptUserId(Long.valueOf(chat.getReceiverId()));
        }
        msgDB.setMsg(chat.getMsg());
        msgDB.setSignFlag(MsgSignFlagEnum.UNSIGNED.type);

        chatMsgDao.insert(msgDB);

        return String.valueOf(msgDB.getId());
    }

    /**
     * 批量签收消息
     *
     * @param msgIdsList
     */
    @Override
    public void updateMsgSigned(List<String> msgIdsList) {
        chatMsgDao.batchUpdateMsgSigned(msgIdsList);
    }

    /**
     * 发送通知消息（提示）
     * 用户上线
     * @param channelGroup
     * @param channel
     */
    @Override
    public void sendAddNotify(ChannelGroup channelGroup, Channel channel) {
        channelGroup.add(channel);
    }

    @Override
    public void sendRemoveNotify(ChannelGroup channelGroup, Channel channel) {
        AttributeKey<String> key = AttributeKey.valueOf("user");
        String userId = channel.attr(key).get();
        UserChannelRel.remove(userId);
        channelGroup.remove(channel);

        DataContent content = new DataContent();
        ChatMsgVo chat = new ChatMsgVo();
        chat.setMsg(String.format(
                "%s【客户端】离开了，当前在线人数%s\n", formatter.format(LocalDateTime.now()), channelGroup.size()));
        content.setChatMsg(chat);
        content.setExtand(String.valueOf(MsgActionEnum.SYSTEM.type));
        // 将该客户加入聊天的信息推送给其它在线的客户端
        // 该方法会将 channelGroup 中所有的channel遍历并发送消息
        channelGroup.writeAndFlush(
                new TextWebSocketFrame(JSONUtil.toJsonStr(content)));
        log.info("channelGroup Size" + channelGroup.size());
    }

    @Override
    public void sendNotify(ChannelGroup channelGroup, DataContent dataContent, Channel channel) {
        // 2.1 当websocket 第一次open的时候，初始化channel，把userId 或者 roomId 和 channel关联起来
        if (Objects.equals(dataContent.getChatMsg().getMsgType(), MsgTypeEnum.CHAT_CONNECT.type)) {
            String sendUserId = dataContent.getChatMsg().getSenderId();
            UserChannelRel.put(sendUserId, channel);
            ChatMsgVo msgVo = new ChatMsgVo();
            msgVo.setMsg("恭喜你们成为好友！");
            dataContent.setChatMsg(msgVo);
            dataContent.setExtand(String.valueOf(MsgActionEnum.SYSTEM.type));
            channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(dataContent)));
        } else if (Objects.equals(dataContent.getChatMsg().getMsgType(), MsgTypeEnum.GROUP_CHAT_CONNECT.type)) {
            String sendUserId = dataContent.getChatMsg().getSenderId();
            String roomId = dataContent.getChatMsg().getReceiverId();
            UserGroupChannelRel.put(roomId, sendUserId, channel);
            ChatMsgVo msgVo = new ChatMsgVo();
            msgVo.setMsg("欢迎加入群聊！");
            dataContent.setChatMsg(msgVo);
            dataContent.setExtand(String.valueOf(MsgActionEnum.SYSTEM.type));
            channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(dataContent)));
        }
    }

    @Override
    public void sendMessage(ChannelGroup channelGroup, Channel channel, DataContent dataContent) {
        switch (dataContent.getChatMsg().getMsgType()) {
            case MsgTypeConstant.TEXT_MSG:
                sendTextMessage(channelGroup, channel, dataContent);
                break;

            case MsgTypeConstant.IMAGE_MSG:
                break;

            case MsgTypeConstant.VOICE_MSG:
                break;

            case MsgTypeConstant.VIDEO_MSG:
                break;

            case MsgTypeConstant.ADDRESS_MSG:
                break;

            case MsgTypeConstant.FILE_MSG:
                break;

            case MsgTypeConstant.HINT_MSG:
                break;

            case MsgTypeConstant.DIY_MSG:
                break;
        }
    }

    @Override
    public void sendGroupMessage(ChannelGroup channelGroup, Channel channel, DataContent dataContent) {
        ChatMsgVo chat = dataContent.getChatMsg();
        String roomId = chat.getReceiverId();
        // 保存消息到数据库，并且标记为未签收
        String msgId = saveMsg(chat);
        chat.setMsgId(msgId);
        // 获取channel 组
        Map<String, Channel> channelMap = UserGroupChannelRel.get(roomId);

        channelMap.forEach((sedUserId, receiverChannel) -> {
            log.info("===============================》" + receiverChannel.id().asLongText());
            receiverChannel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(dataContent)));
        });
    }

    private void sendTextMessage(ChannelGroup channelGroup, Channel channel, DataContent dataContent) {
        ChatMsgVo chat = dataContent.getChatMsg();
        String receiverId = chat.getReceiverId();
        // 保存消息到数据库，并且标记为未签收
        String msgId = saveMsg(chat);
        chat.setMsgId(msgId);
        log.info("=====================>" + chat.toString());
        Channel receiverChannel = UserChannelRel.get(receiverId);
        if (receiverChannel == null || !UserChannelRel.hasUser(channel)) {
            // TODO channel 为空代表用户离线，推送消息(RabbitMq)
            log.info(channel.remoteAddress() + formatter.format(LocalDateTime.now()) + "下线了~");
        } else {
            Channel findCh = channelGroup.find(receiverChannel.id());
            if (findCh != null) {
                // 用户在线
                receiverChannel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(dataContent)));
            } else {
                // TODO channel 为空代表用户离线，推送消息(RabbitMq, 个推，米推)
                log.info(channel.remoteAddress() + formatter.format(LocalDateTime.now()) + "下线了~");
            }
        }
    }
}